package lol_stream_manager;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImageFinder {

        // distance taking into accoutn the brightness difference of the pixels (not the global brightness dif)
    public static double maxBrightness = 50d;
    public static double distanceWithBrightness( double[][][] global, double[][][] interior, int xMin, int yMin ){
        double d = 0;
        for(int x=5 ; x<interior.length-5 ; x++)
            for(int y=5 ; y<interior[0].length-5 ; y++)
                if( x > (interior.length)/3 || y < (interior[0].length*2)/3 ){
                    double brightness = 0;
                    double[] tmp = new double[3];
                    for(int i=0 ; i<3 ; i++){
                        double dif = global[x+xMin][y+yMin][i] - interior[x][y][i];
                        tmp[i] = dif;
                        brightness += dif;
                    }
                    brightness /= 3d;
                    brightness = Math.min(brightness, maxBrightness);
                    brightness = Math.max(brightness, -maxBrightness);
                    for(int i=0 ; i<3 ; i++){
                        //d += Math.abs(global[x+xMin][y+yMin][i] - interior[x][y][i] );
                        double dif = tmp[i] - brightness;
                        d += dif * dif;
                    }
                }
        return d/((double)(interior.length-10)*(interior.length-10));
    }
    
    public static double distance( double[][][] global, double[][][] interior, int xMin, int yMin){
        double d = 0;
        double[] tmp = null;
        for(int x=0 ; x<interior.length ; x++)
            for(int y=0 ; y<interior[0].length ; y++)
                for(int i=0 ; i<3 ; i++)
                    d += (global[x+xMin][y+yMin][i] - interior[x][y][i] )*(global[x+xMin][y+yMin][i] - interior[x][y][i] );
        return d;
    }

    // B & W images distance
    public static double distanceBW( double[][][] global, double[][][] interior, int xMin, int yMin ){
        double d = 0;
        for(int x=5 ; x<interior.length-5 ; x++)
            for(int y=5 ; y<interior[0].length-5 ; y++)
                if( x > (interior.length)/3 || y < (interior[0].length*2)/3 ){
                    double dif = global[x+xMin][y+yMin][0] - interior[x][y][0];
                    d += dif * dif;
                }
        return d/((double)(interior.length-10)*(interior.length-10));
    }
    
    public static double[] minDist( double[][][] global, double[][][] interior ){
        double d = Double.MAX_VALUE;
        double minX = 0;
        double minY = 0;
        for(int x=0 ; x < global.length - interior.length ; x++)
            for(int y=0 ; y < global[0].length - interior[0].length ; y++){
                double tmp = distance(global, interior, x, y);
                if( tmp < d ){
                    d = tmp;
                    minX = x;
                    minY = y;
                }
            }
        return new double[] {d, minX, minY};
    }
    
    public static double[] minResized( double[][][] global, BufferedImage toResize ){
        double[] p = new double[4];
        p[0] = Double.MAX_VALUE;
        for(int i=40 ; i<80 ; i++){
            BufferedImage resized = resizeImage(toResize, i, i);
            double[][][] pixels = getPixels( resized );
            double[] tmp = minDist(global, pixels);
            if(tmp[0] < p[0]){
                p[0] = tmp[0];
                p[1] = tmp[1];
                p[2] = tmp[2];
                p[3] = i;
            }
        }
        return p;
    }
    
    public static String bestImage( String name, BufferedImage image ) throws IOException{
        double[][][] pixels = getPixels(image);
        double[] minDist = new double[4];
        minDist[0] = Double.MAX_VALUE;
        String minImage = "";
        File iconDir = new File("C:\\icons");

        if(LOL_Stream_Manager.config.containsKey( name + "X") ){
            int x = (int)Double.parseDouble(LOL_Stream_Manager.config.getProperty( name + "X" ));
            int y = (int)Double.parseDouble(LOL_Stream_Manager.config.getProperty( name + "Y" ));
            int d = (int)Double.parseDouble(LOL_Stream_Manager.config.getProperty( name + "D" ));
            System.out.println(name + " stream info found: " + x + "*" + y + " @ " + d);
            
            for(File icon : iconDir.listFiles()){
                BufferedImage current = ImageIO.read( icon );
                BufferedImage resized = resizeImage(current, d, d);
                double[][][] tmp = getPixels(resized);
                double tmpDist = distance( pixels, tmp, x, y );
                if(tmpDist < minDist[0]){
                    minDist[0] = tmpDist;
                    minImage = icon.getName();
                }
                //System.out.println(icon.getName() + ": " + tmpDist);
            }
        } else {
            System.out.println(name + " stream info not found. Generating...");
            File[] files = iconDir.listFiles();
            int nFile = files.length;
            int iFile = 1;
            for(File icon : files){
                BufferedImage current = ImageIO.read( icon );
                double tmpDist[] = minResized( pixels, current );
                if(tmpDist[0] < minDist[0]){
                    minDist = tmpDist;
                    minImage = icon.getName();
                }
                Utility.drawProgressBar(iFile++, nFile);
                //System.out.println(icon.getName() + ": " + tmpDist[0] + " [" + tmpDist[1] + "*" + tmpDist[2] + "] @ " + tmpDist[3]);
            }

            if( minDist[0] < 4000){
                LOL_Stream_Manager.config.setProperty(name + "X", ""+minDist[1]);
                LOL_Stream_Manager.config.setProperty(name + "Y", ""+minDist[2]);
                LOL_Stream_Manager.config.setProperty(name + "D", ""+minDist[3]);
                
                LOL_Stream_Manager.config.store(new FileOutputStream("settings.txt"), null);
                System.out.println(name + " stream info created: " + minDist[1] + "*" + minDist[2] + " @ " + minDist[3]);
            } else {
                System.out.println(name + ": can't create stream info, result are not good enough.");
            }
        }
        
        if( minDist[0] > 5000 ){
            LOL_Stream_Manager.results[1].add(new String[] {name});
            return " probably not playing lol (" 
                    + minImage.substring(0, minImage.length()-10) + " @ " + minDist[0] + ")";
        }
        else{
            LOL_Stream_Manager.results[2].add(new String[] {name, minImage.replace("Square.png", "")});
            return " plays " + minImage.substring(0, minImage.length() - 10) + " @ " + minDist[0] + ")";
        }
    }
    
    public static double[] empty = null;
    public static double[][][] getPixels( BufferedImage image ){
        Raster raster = image.getRaster();
        double[][][] pixels = new double[raster.getWidth()][raster.getHeight()][3];
        for(int x=0 ; x<image.getWidth() ; x++)
            for(int y=0 ; y<image.getHeight() ; y++)
                pixels[x][y] = raster.getPixel(x, y, empty);
        return pixels;
    }

    public static double[][][] getPixelsBW( BufferedImage image ){
        Raster raster = image.getRaster();
        double[][][] pixels = new double[raster.getWidth()][raster.getHeight()][1];
        for(int x=0 ; x<image.getWidth() ; x++)
            for(int y=0 ; y<image.getHeight() ; y++){
                double[] tmp = raster.getPixel(x, y, empty); 
                pixels[x][y][0] = 0.2126*tmp[0] + 0.7152*tmp[1] + 0.0722*tmp[2];
            }
        return pixels;
    }
    
    
    public static BufferedImage resizeImage( BufferedImage originalImage, int width, int height ){
	BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
	Graphics2D g = resizedImage.createGraphics();
	g.drawImage(originalImage, 0, 0, width, height, null);
	g.dispose();
	return resizedImage;
    }
    
    public static double getBrightness( BufferedImage image ){
        double[][][] pixels = getPixels(image);
        double min = Double.MAX_VALUE;
        for(int x=0 ; x<pixels.length ; x++)
            for(int y=0 ; y<pixels[0].length ; y++){
                double tmp = ( pixels[x][y][0] + pixels[x][y][1] + pixels[x][y][2] ) / 3;
                min = Math.min(min, tmp);
            }
        return min;
    }
}
